package com.personalkeeper;

import java.util.Date;

import com.personalkeeper.DatabaseWriter.StatisticsRecord;
import com.personalkeeper.HistoryProvider.LocationHistory;
import com.personalkeeper.HistoryProvider.Statistics;
import com.personalkeeper.HistoryProvider.TrackingSession;
import com.personalkeeper.PersonalKeeper.Utils;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;

public class StatisticsCalculator {

    public static class DistanceAndTime {
        private double mDistance;
        private long mTime;

        public DistanceAndTime(double distance, long time) {
            this.mDistance = distance;
            this.mTime = time;
        }

        public double getDistance() {
            return mDistance;
        }

        public void setDistance(double distance) {
            this.mDistance = distance;
        }

        public long getTime() {
            return mTime;
        }

        public void setTime(long time) {
            this.mTime = time;
        }
    }

    public static DistanceAndTime calculateStatistics(Context context, long from, long to) {
        double resultDistance = 0;
        long resultTime = 0;
        Cursor c = context.getContentResolver().query(
                       LocationHistory.CONTENT_URI,
                       new String[] { LocationHistory.LATITUDE, LocationHistory.LONGITUDE, LocationHistory.DATE },
                       LocationHistory.DATE + " >= " + from + " and " + LocationHistory.DATE + " < " + to,
                       null,
                       null);
        try {
            int latitudeID = c.getColumnIndexOrThrow(LocationHistory.LATITUDE);
            int longitudeID = c.getColumnIndexOrThrow(LocationHistory.LONGITUDE);
            int dateID = c.getColumnIndexOrThrow(LocationHistory.DATE);
            if (c.moveToFirst()) {
                boolean firstIteration = true;
                double prevLatitude = 0;
                double prevLongitude = 0;
                long prevDate = 0;

                do {
                    double currentLatitude = c.getDouble(latitudeID);
                    double currentLongitude = c.getDouble(longitudeID);
                    double currentDate = c.getLong(dateID);

                    if (firstIteration) {
                        firstIteration = false;
                    } else {
                        resultDistance += Utils.distanceBetween(
                                              currentLatitude,
                                              currentLongitude,
                                              prevLatitude,
                                              prevLongitude);
                        resultTime += currentDate - prevDate;
                    }
                    prevLatitude = currentLatitude;
                    prevLongitude = currentLongitude;
                } while (c.moveToNext());
            }
        } finally {
            c.close();
        }
        return new DistanceAndTime(resultDistance, resultTime);
    }

    public static DistanceAndTime getSessionStatisticsSince(Context context, long since) {
        Cursor c = context.getContentResolver().query(
                       TrackingSession.Summary.CONTENT_URI,
                       null,
                       TrackingSession.START_DATE + " >= " + since,
                       null,
                       null);
        try {
            if (c.moveToFirst())
                return new DistanceAndTime(c.getDouble(0), c.getLong(1));
            else
                return new DistanceAndTime(0, 0);
        } finally {
            c.close();
        }
    }

    @Deprecated
    public static double getDailyStatistics(Context context, int year, int month, int day) {
        Double cache = getDailyStatisticsCache(context, year, month, day);
        if (cache == null) {
            double result = calculateStatistics(context,
                                                new Date(year, month, day).getTime(),
                                                new Date(year, month, day + 1).getTime()).getDistance();
            boolean today = new Date().compareTo(new Date(year, month, day + 1)) < 0;
            if (!today) {
                DatabaseWriter writer = new DatabaseWriter(context);
                writer.insert(new StatisticsRecord(StatisticsRecord.Type.DAILY, new Date(year, month, day), result));
            }

            return result;
        } else
            return cache;
    }

    @Deprecated
    public static double getMonthlyStatistics(Context context, int year, int month) {
        Double cache = getMonthlyStatisticsCache(context, year, month);
        if (cache == null) {
            double result = calculateStatistics(context,
                                                new Date(year, month, 1).getTime(),
                                                new Date(year, month + 1, 1).getTime()).getDistance();
            boolean thisMonth = new Date().compareTo(new Date(year, month + 1, 1)) < 0;
            if (!thisMonth) {
                DatabaseWriter writer = new DatabaseWriter(context);
                writer.insert(new StatisticsRecord(StatisticsRecord.Type.MONTHLY, new Date(year, month, 1), result));
            }

            return result;
        } else
            return cache;
    }

    @Deprecated
    public static Double getDailyStatisticsCache(Context context, int year, int month, int day) {
        return getStatisticsCache(context, StatisticsRecord.Type.DAILY, new Date(year, month, day).getTime());
    }

    @Deprecated
    public static Double getMonthlyStatisticsCache(Context context, int year, int month) {
        return getStatisticsCache(context, StatisticsRecord.Type.MONTHLY, new Date(year, month, 1).getTime());
    }

    @Deprecated
    private static Double getStatisticsCache(Context context, StatisticsRecord.Type type, long time) {
        Cursor c = context.getContentResolver().query(
                       Statistics.CONTENT_URI,
                       new String[] { Statistics.DISTANCE },
                       Statistics.DATE + " = " + time + " and " + Statistics.TYPE + " = " + type.toString(),
                       null,
                       null);
        Double result = null;
        try {
            if (c.moveToFirst()) {
                int distanceID = c.getColumnIndexOrThrow(Statistics.DISTANCE);
                result = c.getDouble(distanceID);
            }
            return result;
        } finally {
            c.close();
        }
    }

}
